// package: rewords-server-2024
// filename: sys
// author: diogoxiang@gmail.com
// time: 2024/7/12 下午2:35

package sys

import (
	"context"
	"encoding/json"

	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/util/gconv"

	"rewords-server-2024/internal/consts"
	"rewords-server-2024/internal/library/contexts"
	"rewords-server-2024/internal/library/location"
	"rewords-server-2024/internal/library/queue"
	"rewords-server-2024/internal/model/entity"
	"rewords-server-2024/internal/service"
	"rewords-server-2024/utility/validate"
)

type sSysLog struct{}

func NewSysLog() *sSysLog {
	return &sSysLog{}
}

func init() {
	service.RegisterSysLog(NewSysLog())
}

// RealWrite 真实写入
func (s *sSysLog) RealWrite(ctx context.Context, commonLog entity.SysLog) (err error) {
	//_, err = dao.SysLog.Ctx(ctx).Data(commonLog).Insert()
	g.Log().Info(ctx, commonLog)
	return
}

// AutoLog 根据配置自动记录请求日志
func (s *sSysLog) AutoLog(ctx context.Context) error {
	return g.Try(ctx, func(ctx context.Context) {
		var err error
		defer func() {
			if err != nil {
				panic(err)
			}
		}()

		config, err := service.SysConfig().GetLoadLog(ctx)

		if err != nil {
			return
		}

		if !config.Switch {
			return
		}

		data := s.AnalysisLog(ctx)
		if ok := validate.InSliceExistStr(config.Module, data.Module); !ok {
			return
		}

		if ok := validate.InSliceExistStr(config.SkipCode, gconv.String(data.ErrorCode)); ok {
			return
		}

		if config.Queue {
			err = queue.Push(consts.QueueLogTopic, data)
			return
		}

		err = s.RealWrite(ctx, data)
		return
	})
}

// AnalysisLog 解析日志数据
func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
	var (
		modelContext = contexts.Get(ctx)
		response     = modelContext.Response
		user         = modelContext.User
		request      = ghttp.RequestFromCtx(ctx)
		module       = modelContext.Module
		clientIp     = location.GetClientIp(request)
		postData     = gjson.New(request.GetBodyString())
		getData      = gjson.New(request.URL.Query())
		headerData   = gjson.New(consts.NilJsonToString)
		errorData    = gjson.New(consts.NilJsonToString)
		data         entity.SysLog
		memberId     int64
		errorCode    int
		errorMsg     string
		traceID      string
		timestamp    int64
		appId        string
	)

	// 响应数据
	if response != nil {
		errorCode = response.Code
		errorMsg = response.Message
		traceID = response.TraceID
		timestamp = response.Timestamp
		if len(gconv.String(response.Error)) > 0 {
			errorData = gjson.New(response.Error)
		}
	}

	// 请求头
	if reqHeadersBytes, _ := json.Marshal(request.Header); len(gconv.String(reqHeadersBytes)) > 0 {
		headerData = gjson.New(reqHeadersBytes)
	}

	// post参数
	postForm := gjson.New(gconv.String(request.PostForm)).Map()
	if len(postForm) > 0 {
		for k, v := range postForm {
			postData.MustAppend(k, v)
		}
	}
	if postData.IsNil() || len(postData.Map()) == 0 {
		postData = gjson.New(consts.NilJsonToString)
	}

	// 当前登录用户
	if user != nil {
		memberId = user.Uid
		appId = user.App
	}

	ipData, err := location.GetLocation(ctx, clientIp)
	if err != nil {
		g.Log().Errorf(ctx, "location.GetLocation err:%+v", err)
	}
	if ipData == nil {
		ipData = new(location.IpLocationData)
	}

	data = entity.SysLog{
		AppId:      appId,
		MerchantId: 0,
		MemberId:   memberId,
		Method:     request.Method,
		Module:     module,
		Url:        request.RequestURI,
		GetData:    getData,
		PostData:   postData,
		HeaderData: headerData,
		Ip:         clientIp,
		ProvinceId: ipData.ProvinceCode,
		CityId:     ipData.CityCode,
		ErrorCode:  errorCode,
		ErrorMsg:   errorMsg,
		ErrorData:  errorData,
		ReqId:      traceID,
		Timestamp:  timestamp,
		UserAgent:  request.Header.Get("User-Agent"),
		Status:     consts.StatusEnabled,
		TakeUpTime: modelContext.TakeUpTime,
	}
	return data
}
